Hyödynnä useRefin teho Reactissa. Tutustu käyttökohteisiin, kuten DOM-manipulointiin, muuttuvien arvojen ylläpitoon ja funktionaalisten komponenttien optimointiin.
React useRef: Muuttuvien arvojen tallennusmallien hallinta
useRef on tehokas koukku (hook) Reactissa, joka tarjoaa tavan säilyttää arvoja renderöintien välillä ilman, että arvojen muutokset aiheuttavat uudelleenrenderöintiä. Se yhdistetään usein suoraan DOM-elementtien käyttöön, mutta sen kyvyt ulottuvat paljon pidemmälle. Tämä kattava opas syventyy useRef:n monipuolisiin käyttötapauksiin, antaen sinulle valmiudet kirjoittaa tehokkaampaa ja ylläpidettävämpää React-koodia.
useRef:n ymmärtäminen: Enemmän kuin vain DOM-pääsy
Ytimessään useRef palauttaa muuttuvan ref-olion, jonka .current-ominaisuus alustetaan annetulla argumentilla (initialValue). Palautettu olio säilyy koko komponentin elinkaaren ajan. Ratkaisevaa on, että .current-ominaisuuden muokkaaminen ei käynnistä uudelleenrenderöintiä. Tämä on keskeinen ero useRef:n ja useState:n välillä.
Vaikka DOM-elementtien käyttö on yleinen käyttötapaus, useRef loistaa minkä tahansa muuttuvan arvon hallinnassa, jonka ei tarvitse aiheuttaa uudelleenrenderöintiä päivitettäessä. Tämä tekee siitä korvaamattoman arvokkaan tehtävissä, kuten:
- Aiempien prop- tai state-arvojen tallentaminen.
- Laskurien tai ajastimien ylläpitäminen.
- Fokustilan seuraaminen ilman uudelleenrenderöintejä.
- Minkä tahansa muuttuvan arvon tallentaminen, jonka on säilyttävä renderöintien välillä.
Peruskäyttö: DOM-elementtien käyttö
Tunnetuin käyttötapaus on DOM-elementtien suora käyttö. Tämä on hyödyllistä tilanteissa, joissa sinun on vuorovaikutettava imperatiivisesti DOM-solmun kanssa, kuten syöttökentän kohdistaminen, sen mittojen mittaaminen tai animaatioiden käynnistäminen.
Esimerkki: Syöttökentän kohdistaminen
Näin voit käyttää useRef:iä syöttökentän kohdistamiseen, kun komponentti liitetään (mount):
import React, { useRef, useEffect } from 'react';
function MyComponent() {
const inputRef = useRef(null);
useEffect(() => {
// Kohdista syöttökenttä liittämisen yhteydessä
if (inputRef.current) {
inputRef.current.focus();
}
}, []); // Tyhjä riippuvuustaulukko varmistaa, että tämä suoritetaan vain kerran liittämisen yhteydessä
return (
<input type="text" ref={inputRef} placeholder="Syötä tekstiä" />
);
}
export default MyComponent;
Selitys:
- Luomme refin käyttämällä
useRef(null). Alkuarvo onnull, koska syöttöelementtiä ei ole vielä olemassa, kun komponentti alun perin renderöidään. - Liitämme refin syöttöelementtiin käyttämällä
ref-proppia:ref={inputRef}. React asettaa automaattisestiinputRef.current:n DOM-solmuksi, kun syöttöelementti liitetään. - Käytämme
useEffect:iä tyhjällä riippuvuustaulukolla ([]) varmistaaksemme, että efekti suoritetaan vain kerran komponentin liittämisen jälkeen. - Efektin sisällä tarkistamme, onko
inputRef.currentolemassa (välttääksemme virheitä, jos elementti ei ole vielä saatavilla) ja kutsumme sitteninputRef.current.focus()kohdistaaksemme syöttökentän.
DOM-pääsyn tuolla puolen: Muuttuvien arvojen hallinta
useRef:n todellinen voima piilee sen kyvyssä tallentaa muuttuvia arvoja, jotka säilyvät renderöintien välillä käynnistämättä uudelleenrenderöintejä. Tämä avaa laajan valikoiman mahdollisuuksia komponenttien toiminnan optimointiin ja tilan hallintaan funktionaalisissa komponenteissa.
Esimerkki: Aiempien prop- tai state-arvojen tallentaminen
Joskus sinun on päästävä käsiksi propin tai tilamuuttujan edelliseen arvoon. useRef tarjoaa siistin tavan tehdä tämä ilman tarpeettomien uudelleenrenderöintien käynnistämistä.
import React, { useRef, useEffect } from 'react';
function MyComponent({ value }) {
const previousValue = useRef(value);
useEffect(() => {
// Päivitä refin .current-ominaisuus nykyisellä arvolla
previousValue.current = value;
}, [value]); // Efekti suoritetaan aina, kun 'value'-proppi muuttuu
// Nyt voit käyttää edellistä arvoa previousValue.current-muuttujan kautta
return (
<div>
Nykyinen arvo: {value}
<br />
Edellinen arvo: {previousValue.current}
</div>
);
}
export default MyComponent;
Selitys:
- Alustamme
previousValue-refinvalue-propin alkuarvolla. - Käytämme
useEffect:iä päivittääksemmepreviousValue.current-ominaisuuden aina, kunvalue-proppi muuttuu. - Komponentin sisällä voimme nyt käyttää
value-propin edellistä arvoapreviousValue.current-muuttujan kautta.
Käyttötapauksen esimerkki: API-vastausten muutosten seuraaminen (kansainvälinen skenaario)
Kuvittele rakentavasi kojelautaa, joka näyttää API:sta haettuja valuuttakursseja. API saattaa palauttaa kurssit eri muodoissa tai vaihtelevalla tarkkuudella riippuen tietolähteestä (esim. Euroopan keskuspankin API vs. Kaakkois-Aasian rahoituslaitoksen API). Voit käyttää useRef:iä edellisen valuuttakurssin seuraamiseen ja näyttää visuaalisen ilmaisimen (esim. vihreän ylänuolen tai punaisen alanuolen) osoittamaan, onko kurssi noussut vai laskenut edellisen päivityksen jälkeen. Tämä on ratkaisevan tärkeää kansainvälisille käyttäjille, jotka tukeutuvat näihin kursseihin taloudellisissa päätöksissään.
Esimerkki: Laskurien tai ajastimien ylläpitäminen
useRef on täydellinen sellaisten laskurien tai ajastimien hallintaan, joiden ei tarvitse käynnistää uudelleenrenderöintejä. Voit esimerkiksi käyttää sitä seuraamaan, kuinka monta kertaa nappia on painettu, tai toteuttaa yksinkertaisen ajastimen.
import React, { useRef, useState, useEffect } from 'react';
function MyComponent() {
const [count, setCount] = useState(0);
const clickCount = useRef(0); // Alusta ref arvolla 0
const handleClick = () => {
clickCount.current++; // Kasvata refin .current-ominaisuutta
setCount(clickCount.current); //Kasvata tilaa (state), mikä aiheuttaa uudelleenrenderöinnin.
};
return (
<div>
<p>Nappia painettu: {count} kertaa</p>
<button onClick={handleClick}>Paina minua</button>
</div>
);
}
export default MyComponent;
Selitys:
- Alustamme
clickCount-refin arvolla 0. handleClick-funktiossa kasvatammeclickCount.current-ominaisuutta. Tämä ei käynnistä uudelleenrenderöintiä.- Päivitämme myös 'count'-tilaa, mikä käynnistää uudelleenrenderöinnin.
Esimerkki: Debounce-funktion toteuttaminen
Debouncing on tekniikka, jota käytetään rajoittamaan funktion suoritustiheyttä. Sitä käytetään yleisesti hakukentissä estämään liiallisia API-kutsuja käyttäjän kirjoittaessa. useRef:iä voidaan käyttää debounce-funktion käyttämän ajastimen ID:n tallentamiseen.
import React, { useState, useRef, useEffect } from 'react';
function MyComponent() {
const [searchTerm, setSearchTerm] = useState('');
const [results, setResults] = useState([]);
const timerRef = useRef(null); // Tallenna ajastimen ID
const handleChange = (event) => {
const newSearchTerm = event.target.value;
setSearchTerm(newSearchTerm);
// Tyhjennä edellinen ajastin, jos se on olemassa
if (timerRef.current) {
clearTimeout(timerRef.current);
}
// Aseta uusi ajastin
timerRef.current = setTimeout(() => {
// Simuloi API-kutsua
fetch(`https://api.example.com/search?q=${newSearchTerm}`)
.then(response => response.json())
.then(data => setResults(data.results));
}, 300); // Debounce 300 millisekuntia
};
return (
<div>
<input
type="text"
placeholder="Hae..."
value={searchTerm}
onChange={handleChange}
/>
<ul>
{results.map(result => (
<li key={result.id}>{result.name}</li>
))}
</ul>
</div>
);
}
export default MyComponent;
Selitys:
- Käytämme
useRef:iä tallentaaksemme ajastimen ID:ntimerRef-muuttujaan. handleChange-funktiossa tyhjennämme edellisen ajastimen (jos se on olemassa) käyttämälläclearTimeout(timerRef.current).- Asetamme sitten uuden ajastimen käyttämällä
setTimeoutja tallennamme ajastimen ID:ntimerRef.current-muuttujaan. - API-kutsu tehdään vasta, kun käyttäjä on lopettanut kirjoittamisen 300 millisekunnin ajaksi.
Kansainvälistämiseen liittyviä huomioita: Kun toteutat debounce-toimintoa API-kutsuilla, jotka näyttävät tietoa eri kielillä, varmista, että API tukee kansainvälistämistä ja palauttaa dataa käyttäjän haluamalla kielellä. Harkitse Accept-Language-otsakkeen käyttöä API-pyynnöissäsi.
Esimerkki: Fokustilan seuraaminen ilman uudelleenrenderöintejä
Voit käyttää useRef:iä seuraamaan, onko elementillä fokus, ilman että se aiheuttaa uudelleenrenderöintejä. Tämä voi olla hyödyllistä elementtien tyylittelyssä niiden fokustilan perusteella tai mukautetun fokuksenhallintalogiikan toteuttamisessa.
import React, { useRef, useState } from 'react';
function MyComponent() {
const [isFocused, setIsFocused] = useState(false);
const inputRef = useRef(null);
const handleFocus = () => {
setIsFocused(true);
};
const handleBlur = () => {
setIsFocused(false);
};
return (
<div>
<input
type="text"
ref={inputRef}
onFocus={handleFocus}
onBlur={handleBlur}
/>
<p>Syöttökenttä on kohdistettu: {isFocused ? 'Kyllä' : 'Ei'}</p>
</div>
);
}
export default MyComponent;
useRef vs. useState: Oikean työkalun valinta
On tärkeää ymmärtää keskeiset erot useRef:n ja useState:n välillä, jotta osaat valita oikean työkalun kuhunkin tehtävään.
| Ominaisuus | useRef | useState |
|---|---|---|
| Käynnistää uudelleenrenderöinnin | Ei | Kyllä |
| Tarkoitus | Muuttuvien arvojen tallentaminen, joiden ei tarvitse käynnistää uudelleenrenderöintiä. DOM-elementtien käyttö. | Tilan hallinta, jonka on tarkoitus käynnistää uudelleenrenderöinti. |
| Pysyvyys | Säilyy uudelleenrenderöintien yli. | Säilyy uudelleenrenderöintien yli, mutta arvo päivitetään asetusfunktiolla. |
Parhaat käytännöt ja yleisimmät sudenkuopat
- Älä muuta tilaa suoraan: Vaikka
useRefantaa sinun muuttaa arvoja suoraan, vältäuseState:n hallinnoimien tilamuuttujien suoraa muuttamista. Käytä ainauseState:n tarjoamaa asetusfunktiota tilan päivittämiseen. - Ole tietoinen sivuvaikutuksista: Kun käytät
useRef:iä hallitaksesi arvoja, jotka vaikuttavat käyttöliittymään, ole tietoinen mahdollisista sivuvaikutuksista. Varmista, että koodisi toimii ennustettavasti eikä aiheuta odottamattomia bugeja. - Älä luota
useRef:iin renderöintilogiikassa: KoskauseRef:n muutokset eivät käynnistä uudelleenrenderöintejä, älä luota sen arvoihin suoraan päättäessäsi, mitä tulisi renderöidä. KäytäuseState:a arvoille, joiden on ohjattava renderöintilogiikkaa. - Harkitse suorituskykyvaikutuksia: Vaikka
useRefvoi auttaa optimoimaan suorituskykyä estämällä tarpeettomia uudelleenrenderöintejä, ole tietoinen siitä, että muuttuvien arvojen liiallinen käyttö voi tehdä koodistasi vaikeammin ymmärrettävää ja debugattavaa.
Edistyneet käyttötapaukset ja mallit
Arvojen säilyttäminen komponentti-instanssien välillä
Vaikka `useRef` säilyttää arvot *yhden* komponentti-instanssin renderöintien yli, joskus tarvitset arvon säilyvän saman komponentin *eri* instanssien välillä. Tämä vaatii hieman erilaista lähestymistapaa, usein hyödyntäen moduulitason muuttujaa yhdessä `useRef`:n kanssa.
// myComponent.js
let globalCounter = 0; // Moduulitason muuttuja
import React, { useRef, useEffect } from 'react';
function MyComponent() {
const counterRef = useRef(globalCounter); // Alusta globaalilla arvolla
useEffect(() => {
// Päivitä globaali laskuri aina kun ref muuttuu
globalCounter = counterRef.current;
}, [counterRef.current]);
const increment = () => {
counterRef.current++;
//Ei tarvita setState-kutsua, joten ei uudelleenrenderöintiä
};
return (
<div>
<p>Laskuri: {counterRef.current}</p>
<button onClick={increment}>Kasvata</button>
</div>
);
}
export default MyComponent;
Tärkeitä huomioita: Tämä malli esittelee globaalin muuttujan, joten ole erittäin varovainen mahdollisten sivuvaikutusten ja kilpailutilanteiden suhteen, erityisesti monimutkaisissa sovelluksissa. Harkitse vaihtoehtoisia lähestymistapoja, kuten kontekstiproviderin käyttöä, jos arvoa on jaettava useiden komponenttien välillä hallitummin.
Yhteenveto: useRefin voiman vapauttaminen
useRef on monipuolinen työkalu Reactissa, joka ulottuu paljon pidemmälle kuin pelkkään DOM-elementtien käyttöön. Ymmärtämällä sen kyvyn tallentaa muuttuvia arvoja ilman uudelleenrenderöintien käynnistämistä, voit optimoida komponenttejasi, hallita tilaa tehokkaammin ja rakentaa suorituskykyisempiä ja ylläpidettävämpiä React-sovelluksia. Muista käyttää sitä harkitusti ja harkitse aina suorituskyvyn ja koodin selkeyden välisiä kompromisseja.
Hallitsemalla tässä oppaassa kuvatut mallit olet hyvin varustautunut hyödyntämään useRef:n koko potentiaalia React-projekteissasi, olitpa rakentamassa yksinkertaista verkkosovellusta tai monimutkaista yritysjärjestelmää. Muista ottaa huomioon kansainvälistäminen ja saavutettavuus, kun rakennat globaalille yleisölle!